package com.zenithmind.common.utils;

import com.zenithmind.common.config.SecurityProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 密码验证工具
 * 根据安全策略验证密码强度
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PasswordValidator {
    
    private final SecurityProperties securityProperties;
    
    // 正则表达式模式
    private static final Pattern DIGIT_PATTERN = Pattern.compile(".*\\d.*");
    private static final Pattern LOWERCASE_PATTERN = Pattern.compile(".*[a-z].*");
    private static final Pattern UPPERCASE_PATTERN = Pattern.compile(".*[A-Z].*");
    private static final Pattern SPECIAL_CHAR_PATTERN = Pattern.compile(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*");
    
    /**
     * 验证密码是否符合安全策略
     * 
     * @param password 待验证的密码
     * @return 验证结果
     */
    public PasswordValidationResult validate(String password) {
        List<String> errors = new ArrayList<>();
        
        if (!StringUtils.hasText(password)) {
            errors.add("密码不能为空");
            return new PasswordValidationResult(false, errors);
        }
        
        SecurityProperties.Password passwordConfig = securityProperties.getPassword();
        
        // 检查密码长度
        if (password.length() < passwordConfig.getMinLength()) {
            errors.add(String.format("密码长度不能少于%d位", passwordConfig.getMinLength()));
        }
        
        if (password.length() > passwordConfig.getMaxLength()) {
            errors.add(String.format("密码长度不能超过%d位", passwordConfig.getMaxLength()));
        }
        
        // 检查是否包含数字
        if (passwordConfig.isRequireDigit() && !DIGIT_PATTERN.matcher(password).matches()) {
            errors.add("密码必须包含至少一个数字");
        }
        
        // 检查是否包含小写字母
        if (passwordConfig.isRequireLowercase() && !LOWERCASE_PATTERN.matcher(password).matches()) {
            errors.add("密码必须包含至少一个小写字母");
        }
        
        // 检查是否包含大写字母
        if (passwordConfig.isRequireUppercase() && !UPPERCASE_PATTERN.matcher(password).matches()) {
            errors.add("密码必须包含至少一个大写字母");
        }
        
        // 检查是否包含特殊字符
        if (passwordConfig.isRequireSpecialChar() && !SPECIAL_CHAR_PATTERN.matcher(password).matches()) {
            errors.add("密码必须包含至少一个特殊字符");
        }
        
        // 检查常见弱密码
        if (isCommonWeakPassword(password)) {
            errors.add("密码过于简单，请使用更复杂的密码");
        }
        
        boolean isValid = errors.isEmpty();
        
        if (isValid) {
            log.debug("密码验证通过");
        } else {
            log.debug("密码验证失败: {}", String.join(", ", errors));
        }
        
        return new PasswordValidationResult(isValid, errors);
    }
    
    /**
     * 检查是否为常见弱密码
     */
    private boolean isCommonWeakPassword(String password) {
        String lowerPassword = password.toLowerCase();
        
        // 常见弱密码列表
        String[] weakPasswords = {
            "password", "123456", "123456789", "qwerty", "abc123",
            "password123", "admin", "root", "user", "guest",
            "12345678", "1234567890", "qwertyuiop", "asdfghjkl",
            "zxcvbnm", "111111", "000000", "666666", "888888"
        };
        
        for (String weak : weakPasswords) {
            if (lowerPassword.equals(weak) || lowerPassword.contains(weak)) {
                return true;
            }
        }
        
        // 检查是否为连续字符
        if (isSequentialChars(password) || isRepeatingChars(password)) {
            return true;
        }
        
        return false;
    }
    
    /**
     * 检查是否为连续字符
     */
    private boolean isSequentialChars(String password) {
        if (password.length() < 3) {
            return false;
        }
        
        for (int i = 0; i < password.length() - 2; i++) {
            char c1 = password.charAt(i);
            char c2 = password.charAt(i + 1);
            char c3 = password.charAt(i + 2);
            
            // 检查连续递增或递减
            if ((c2 == c1 + 1 && c3 == c2 + 1) || (c2 == c1 - 1 && c3 == c2 - 1)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查是否为重复字符
     */
    private boolean isRepeatingChars(String password) {
        if (password.length() < 3) {
            return false;
        }
        
        int repeatCount = 1;
        char prevChar = password.charAt(0);
        
        for (int i = 1; i < password.length(); i++) {
            char currentChar = password.charAt(i);
            if (currentChar == prevChar) {
                repeatCount++;
                if (repeatCount >= 3) {
                    return true;
                }
            } else {
                repeatCount = 1;
                prevChar = currentChar;
            }
        }
        
        return false;
    }
    
    /**
     * 计算密码强度分数（0-100）
     */
    public int calculatePasswordStrength(String password) {
        if (!StringUtils.hasText(password)) {
            return 0;
        }
        
        int score = 0;
        
        // 长度分数（最多30分）
        score += Math.min(password.length() * 2, 30);
        
        // 字符类型分数
        if (DIGIT_PATTERN.matcher(password).matches()) score += 15;
        if (LOWERCASE_PATTERN.matcher(password).matches()) score += 15;
        if (UPPERCASE_PATTERN.matcher(password).matches()) score += 15;
        if (SPECIAL_CHAR_PATTERN.matcher(password).matches()) score += 15;
        
        // 复杂度分数
        if (password.length() >= 12) score += 10;
        if (!isCommonWeakPassword(password)) score += 10;
        
        return Math.min(score, 100);
    }
    
    /**
     * 密码验证结果
     */
    public static class PasswordValidationResult {
        private final boolean valid;
        private final List<String> errors;
        
        public PasswordValidationResult(boolean valid, List<String> errors) {
            this.valid = valid;
            this.errors = errors;
        }
        
        public boolean isValid() {
            return valid;
        }
        
        public List<String> getErrors() {
            return errors;
        }
        
        public String getErrorMessage() {
            return String.join("; ", errors);
        }
    }
}
